package cn.iocoder.yudao.module.system.service.gugu;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.controller.admin.gugu.gugu.MajorAdmissionInfo;
import cn.iocoder.yudao.module.system.controller.admin.gugu.gugu.MajorAdmissionQueryReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.gugu.MajorAdmissionDO;
import cn.iocoder.yudao.module.system.dal.mysql.gugu.MajorAdmissionMapper;
import cn.iocoder.yudao.module.system.util.gugu.GuGuDataUtils;
import cn.iocoder.yudao.module.system.util.gugu.MajorNameBracketProcessor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 历年高考专业录取数据 Service 实现类
 */
@Service
@Validated
@Slf4j
public class MajorAdmissionServiceImpl implements MajorAdmissionService {

    @Resource
    private MajorAdmissionMapper majorAdmissionMapper;

    /**
     * 数据获取线程池
     */
    private ExecutorService dataFetchExecutor;

    /**
     * 数据保存线程池
     */
    private ExecutorService dataSaveExecutor;

    /**
     * API请求频率控制 - 最小请求间隔（毫秒）
     */
    private static final long MIN_REQUEST_INTERVAL = 1500; // 1.5 seconds between requests

    /**
     * 页面请求间的额外等待时间（毫秒）
     */
    private static final long PAGE_REQUEST_DELAY = 500; // 0.5 seconds additional delay between page requests

    /**
     * 最后一次请求时间
     */
    private volatile long lastRequestTime = 0;

    @PostConstruct
    public void init() {
        // 初始化线程池 - 根据可用CPU核心数动态调整线程数
        int cpuCores = Runtime.getRuntime().availableProcessors();
        // 减少并发线程数，防止API请求过快
        int fetchCoreSize = Math.min(3, Math.max(2, cpuCores / 2)); // 核心线程数限制在3个以内
        int fetchMaxSize = Math.min(5, fetchCoreSize + 2); // 最大线程数限制在5个以内

        // 使用有界队列和CallerRunsPolicy，避免任务被拒绝
        dataFetchExecutor = new ThreadPoolExecutor(
                fetchCoreSize, // 核心线程数
                fetchMaxSize, // 最大线程数
                60L, // 空闲线程存活时间
                TimeUnit.SECONDS, // 时间单位
                new LinkedBlockingQueue<>(500), // 增加队列容量，避免任务被拒绝
                r -> {
                    Thread t = new Thread(r, "data-fetch-thread-" + r.hashCode());
                    t.setUncaughtExceptionHandler((thread, ex) -> {
                        log.error("数据获取线程[{}]发生未捕获异常: {}", thread.getName(), ex.getMessage(), ex);
                    });
                    return t;
                }, // 增强线程工厂，添加未捕获异常处理
                new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略：在调用者线程中执行任务
        );

        // 数据保存线程池也限制并发数，但增加队列容量
        int saveCoreSize = Math.min(3, Math.max(2, cpuCores / 4)); // 增加核心线程数
        int saveMaxSize = Math.min(6, saveCoreSize + 3); // 增加最大线程数

        dataSaveExecutor = new ThreadPoolExecutor(
                saveCoreSize, // 核心线程数
                saveMaxSize, // 最大线程数
                60L, // 空闲线程存活时间
                TimeUnit.SECONDS, // 时间单位
                new LinkedBlockingQueue<>(1000), // 增加队列容量，避免任务被拒绝
                r -> {
                    Thread t = new Thread(r, "data-save-thread-" + r.hashCode());
                    t.setUncaughtExceptionHandler((thread, ex) -> {
                        log.error("数据保存线程[{}]发生未捕获异常: {}", thread.getName(), ex.getMessage(), ex);
                    });
                    return t;
                }, // 增强线程工厂，添加未捕获异常处理
                new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略：在调用者线程中执行任务
        );

        log.info("初始化线程池完成: 数据获取线程池[{}/{}], 数据保存线程池[{}/{}]",
                fetchCoreSize, fetchMaxSize, saveCoreSize, saveMaxSize);
    }

    @PreDestroy
    public void destroy() {
        // 关闭线程池
        if (dataFetchExecutor != null) {
            dataFetchExecutor.shutdown();
            try {
                if (!dataFetchExecutor.awaitTermination(10, TimeUnit.SECONDS)) {
                    dataFetchExecutor.shutdownNow();
                }
            } catch (InterruptedException e) {
                dataFetchExecutor.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }

        if (dataSaveExecutor != null) {
            dataSaveExecutor.shutdown();
            try {
                if (!dataSaveExecutor.awaitTermination(10, TimeUnit.SECONDS)) {
                    dataSaveExecutor.shutdownNow();
                }
            } catch (InterruptedException e) {
                dataSaveExecutor.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int saveMajorAdmissionList(List<MajorAdmissionInfo> admissionInfoList) {
        if (CollUtil.isEmpty(admissionInfoList)) {
            return 0;
        }

        // 批量转换为DO对象
        List<MajorAdmissionDO> majorAdmissionDOList = new ArrayList<>(admissionInfoList.size());
        for (MajorAdmissionInfo admissionInfo : admissionInfoList) {
            // 转换为DO对象
            MajorAdmissionDO majorAdmissionDO = convertToMajorAdmissionDO(admissionInfo);
            if (majorAdmissionDO != null) {
                majorAdmissionDOList.add(majorAdmissionDO);
            }
        }

        if (majorAdmissionDOList.isEmpty()) {
            return 0;
        }

        // 分批保存数据，每批最多500条
        int batchSize = 500;
        int savedCount = 0;
        for (int i = 0; i < majorAdmissionDOList.size(); i += batchSize) {
            int endIndex = Math.min(i + batchSize, majorAdmissionDOList.size());
            List<MajorAdmissionDO> batch = majorAdmissionDOList.subList(i, endIndex);

            // 批量保存到数据库
            for (MajorAdmissionDO majorAdmissionDO : batch) {
                try {
                    majorAdmissionMapper.insert(majorAdmissionDO);
                    savedCount++;
                } catch (Exception e) {
                    // 记录错误但继续处理其他记录
                    log.warn("保存专业录取数据失败: {}", e.getMessage());
                }
            }
        }

        return savedCount;
    }

    /**
     * 保存或更新专业录取数据列表（先查询是否已存在，存在则更新，不存在则新增）
     *
     * @param admissionInfoList 专业录取数据列表
     * @return 保存或更新的记录数
     */
    @Transactional(rollbackFor = Exception.class)
    public int saveOrUpdateMajorAdmissionList(List<MajorAdmissionInfo> admissionInfoList) {
        if (CollUtil.isEmpty(admissionInfoList)) {
            return 0;
        }

        // 批量转换为DO对象
        List<MajorAdmissionDO> majorAdmissionDOList = new ArrayList<>(admissionInfoList.size());
        for (MajorAdmissionInfo admissionInfo : admissionInfoList) {
            // 转换为DO对象
            MajorAdmissionDO majorAdmissionDO = convertToMajorAdmissionDO(admissionInfo);
            if (majorAdmissionDO != null) {
                majorAdmissionDOList.add(majorAdmissionDO);
            }
        }

        if (majorAdmissionDOList.isEmpty()) {
            return 0;
        }

        // 分批处理数据，每批最多500条
        int batchSize = 500;
        int processedCount = 0;
        for (int i = 0; i < majorAdmissionDOList.size(); i += batchSize) {
            int endIndex = Math.min(i + batchSize, majorAdmissionDOList.size());
            List<MajorAdmissionDO> batch = majorAdmissionDOList.subList(i, endIndex);

            // 逐条检查并保存或更新
            for (MajorAdmissionDO majorAdmissionDO : batch) {
                try {
                    // 先查询是否已存在相同的记录
                    MajorAdmissionDO existingRecord =null;
//                    majorAdmissionMapper.selectByUniqueKey(
//                            majorAdmissionDO.getSchoolUuid(),
//                            majorAdmissionDO.getMajorName(),
//                            majorAdmissionDO.getYear(),
//                            majorAdmissionDO.getProvinceName(),
//                            majorAdmissionDO.getTypeName(),
//                            majorAdmissionDO.getSubjectGroup()
//                    );

                    if (existingRecord != null) {
                        // 记录已存在，执行更新操作
                        majorAdmissionDO.setId(existingRecord.getId());
                        majorAdmissionMapper.updateById(majorAdmissionDO);
                        log.debug("更新专业录取数据: 学校={}, 专业={}, 年份={}",
                                majorAdmissionDO.getSchoolName(), majorAdmissionDO.getMajorName(), majorAdmissionDO.getYear());
                    } else {
                        // 记录不存在，执行新增操作
                        majorAdmissionMapper.insert(majorAdmissionDO);
                        log.info("新增专业录取数据: 学校={}, 专业={}, 年份={}",
                                majorAdmissionDO.getSchoolName(), majorAdmissionDO.getMajorName(), majorAdmissionDO.getYear());
                    }
                    processedCount++;
                } catch (Exception e) {
                    // 记录错误但继续处理其他记录
                    log.warn("保存或更新专业录取数据失败: 学校={}, 专业={}, 年份={}, 错误信息={}",
                            majorAdmissionDO.getSchoolName(), majorAdmissionDO.getMajorName(),
                            majorAdmissionDO.getYear(), e.getMessage());
                }
            }
        }

        return processedCount;
    }

    /**
     * 异步保存专业录取数据
     *
     * @param admissionInfoList 专业录取数据列表
     */
    public void asyncSaveMajorAdmissionList(List<MajorAdmissionInfo> admissionInfoList) {
        if (CollUtil.isEmpty(admissionInfoList)) {
            return;
        }

        try {
            // 检查线程池状态，避免提交到已关闭的线程池
            if (dataSaveExecutor.isShutdown() || dataSaveExecutor.isTerminated()) {
                log.warn("数据保存线程池已关闭，无法提交异步任务，将直接同步保存数据");
                int savedCount = saveOrUpdateMajorAdmissionList(admissionInfoList);
                log.info("同步保存或更新{}条专业录取数据到数据库", savedCount);
                return;
            }

            // 使用CallerRunsPolicy策略，如果线程池满了，会在调用线程中执行任务
            dataSaveExecutor.submit(() -> {
                try {
                    int savedCount = saveOrUpdateMajorAdmissionList(admissionInfoList);
                    log.info("异步保存或更新{}条专业录取数据到数据库", savedCount);
                } catch (Exception e) {
                    log.error("异步保存或更新专业录取数据到数据库失败: {}", e.getMessage(), e);
                }
            });
        } catch (Exception e) {
            log.error("提交异步保存任务失败，将尝试同步保存: {}", e.getMessage(), e);
            try {
                // 如果提交失败，则在当前线程中同步执行
                int savedCount = saveOrUpdateMajorAdmissionList(admissionInfoList);
                log.info("同步保存或更新{}条专业录取数据到数据库", savedCount);
            } catch (Exception ex) {
                log.error("同步保存数据失败: {}", ex.getMessage(), ex);
            }
        }
    }

    @Override
    public Map<String, Object> getMajorAdmissionInfo(MajorAdmissionQueryReqVO reqVO) {
        // 控制API请求频率，避免请求过快触发限流
        controlRequestRate();

        // 调用工具类获取历年高考专业录取数据
        return GuGuDataUtils.getMajorAdmissionInfo(reqVO);
    }

    @Override
    public Map<String, Object> getMajorAdmissionInfoAll(MajorAdmissionQueryReqVO reqVO) {
        Map<String, Object> result = new HashMap<>();
        List<MajorAdmissionInfo> allAdmissionList = new ArrayList<>();

        try {
            // 确保设置了页面大小
            if (reqVO.getPagesize() == null) {
                reqVO.setPagesize(50); // 使用API允许的最大页面大小
            }

            // 确保设置了页码
            if (reqVO.getPageindex() == null) {
                reqVO.setPageindex(1); // 从第一页开始
            }

            // 获取第一页数据，用于获取总数量和总页数
            Map<String, Object> firstPageResult = GuGuDataUtils.getMajorAdmissionInfo(reqVO);

            if (!Boolean.TRUE.equals(firstPageResult.get("success"))) {
                return firstPageResult; // 如果第一页查询失败，直接返回错误
            }

            // 获取总数量和总页数
            int totalCount = (Integer) firstPageResult.get("totalCount");
            int totalPages = (Integer) firstPageResult.get("totalPages");
            int distinctSchoolCount = (Integer) firstPageResult.get("distinctSchoolCount");

            log.info("查询到{}省份的专业录取数据总数量为{}，总页数为{}",
                    reqVO.getEnrollprovince(), totalCount, totalPages);

            // 添加第一页的数据
            List<MajorAdmissionInfo> firstPageList = (List<MajorAdmissionInfo>) firstPageResult.get("admissionList");
            if (firstPageList != null && !firstPageList.isEmpty()) {
                allAdmissionList.addAll(firstPageList);
                log.info("成功获取第1页数据，共{}条记录", firstPageList.size());

                // 异步保存数据到数据库
                asyncSaveMajorAdmissionList(new ArrayList<>(firstPageList));
            }

            // 如果有多页，使用多线程获取其他页的数据
            if (totalPages > 1) {
                // 获取CPU核心数，用于智能控制并发
                int cpuCores = Runtime.getRuntime().availableProcessors();

                // 创建一个线程安全的集合来存储所有页的数据
                final Map<Integer, List<MajorAdmissionInfo>> pageDataMap = new ConcurrentHashMap<>();

                // 创建任务列表
                List<CompletableFuture<Void>> futures = new ArrayList<>();

                // 确定起始页和结束页
                int startPageIndex = 2; // 默认从第2页开始（因为第1页已经获取）
                int endPageIndex = totalPages;

                // 如果指定了起始页，则使用指定的起始页
                if (reqVO.getStartPageIndex() != null && reqVO.getStartPageIndex() > 1) {
                    startPageIndex = reqVO.getStartPageIndex();
                    log.info("使用指定的起始页: {}", startPageIndex);
                }

                // 如果指定了结束页，则使用指定的结束页
                if (reqVO.getEndPageIndex() != null && reqVO.getEndPageIndex() > 0 && reqVO.getEndPageIndex() <= totalPages) {
                    endPageIndex = reqVO.getEndPageIndex();
                    log.info("使用指定的结束页: {}", endPageIndex);
                }

                // 为每一页创建一个任务
                for (int pageIndex = startPageIndex; pageIndex <= endPageIndex; pageIndex++) {
                    final int currentPageIndex = pageIndex;
                    log.info("当前页数{}------------------------总页数{}", pageIndex, totalPages);

                    // 创建并提交任务
                    CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                        try {
                            // 创建当前页的请求参数
                            MajorAdmissionQueryReqVO pageReqVO = new MajorAdmissionQueryReqVO();
                            pageReqVO.setPageindex(currentPageIndex);
                            pageReqVO.setPagesize(reqVO.getPagesize());
                            pageReqVO.setEnrollprovince(reqVO.getEnrollprovince());
                            pageReqVO.setSchoolname(reqVO.getSchoolname());
                            pageReqVO.setMajorname(reqVO.getMajorname());
                            pageReqVO.setMajornamestrict(reqVO.getMajornamestrict());
                            pageReqVO.setSpecialid(reqVO.getSpecialid());
                            pageReqVO.setYear(reqVO.getYear());
                            pageReqVO.setMin(reqVO.getMin());
                            pageReqVO.setBatchname(reqVO.getBatchname());
                            pageReqVO.setTypename(reqVO.getTypename());
                            pageReqVO.setSchooluuid(reqVO.getSchooluuid());
                            pageReqVO.setMinrange(reqVO.getMinrange());
                            pageReqVO.setSubjectselection(reqVO.getSubjectselection());

                            // 控制API请求频率
                            controlRequestRate();

                            // 添加额外的页面请求间隔
                            try {
                                log.debug("页面请求间隔: 等待{}ms", PAGE_REQUEST_DELAY);
                                Thread.sleep(PAGE_REQUEST_DELAY);
                            } catch (InterruptedException e) {
                                Thread.currentThread().interrupt();
                                log.warn("页面请求间隔等待被中断");
                            }

                            // 请求数据
                            Map<String, Object> pageResult = GuGuDataUtils.getMajorAdmissionInfo(pageReqVO);

                            if (Boolean.TRUE.equals(pageResult.get("success"))) {
                                List<MajorAdmissionInfo> pageAdmissionList = (List<MajorAdmissionInfo>) pageResult.get("admissionList");
                                if (pageAdmissionList != null && !pageAdmissionList.isEmpty()) {
                                    // 将数据存入线程安全的Map
                                    pageDataMap.put(currentPageIndex, pageAdmissionList);
                                    log.info("成功获取第{}页数据，共{}条记录--剩余{}页", currentPageIndex, pageAdmissionList.size(),totalPages-currentPageIndex);

                                    // 立即提交异步保存任务，确保数据保存任务被执行
                                    final List<MajorAdmissionInfo> dataToSave = new ArrayList<>(pageAdmissionList);
                                    final int pageIdx = currentPageIndex; // 捕获当前页码，避免闭包问题
                                    try {
                                        // 检查线程池状态
                                        if (dataSaveExecutor.isShutdown() || dataSaveExecutor.isTerminated()) {
                                            log.warn("数据保存线程池已关闭，无法提交异步任务，将直接同步保存第{}页数据", pageIdx);
                                            int savedCount = saveOrUpdateMajorAdmissionList(dataToSave);
                                            log.info("同步保存或更新第{}页的{}条专业录取数据到数据库", pageIdx, savedCount);
                                        } else {
                                            // 使用线程池提交任务
                                            dataSaveExecutor.submit(() -> {
                                                try {
                                                    int savedCount = saveOrUpdateMajorAdmissionList(dataToSave);
                                                    log.info("异步保存或更新第{}页的{}条专业录取数据到数据库", pageIdx, savedCount);
                                                } catch (Exception e) {
                                                    log.error("异步保存或更新第{}页专业录取数据到数据库失败: {}", pageIdx, e.getMessage(), e);
                                                }
                                            });
                                        }
                                    } catch (Exception e) {
                                        log.error("提交第{}页异步保存任务失败，将尝试同步保存: {}", pageIdx, e.getMessage(), e);
                                        try {
                                            // 如果提交失败，则在当前线程中同步执行
                                            int savedCount = saveOrUpdateMajorAdmissionList(dataToSave);
                                            log.info("同步保存或更新第{}页的{}条专业录取数据到数据库", pageIdx, savedCount);
                                        } catch (Exception ex) {
                                            log.error("同步保存第{}页数据失败: {}", pageIdx, ex.getMessage(), ex);
                                        }
                                    }
                                }
                            } else {
                                // 如果单页查询失败，记录错误但不中断整个查询
                                log.error("查询第{}页失败: {}", currentPageIndex, pageResult.get("message"));
                            }
                        } catch (Exception e) {
                            log.error("处理第{}页数据时发生异常", currentPageIndex, e);
                        }
                    }, dataFetchExecutor);

                    futures.add(future);

                    // 智能控制任务提交速度，避免API请求频率过高
                    if (futures.size() % 2 == 0) { // 每提交2个任务后检查一次
                        // 检查当前活跃线程数，如果过多则等待
                        ThreadPoolExecutor executor = (ThreadPoolExecutor) dataFetchExecutor;
                        int activeCount = executor.getActiveCount();
                        int queueSize = executor.getQueue().size();

                        // 更保守的负载控制，降低并发量
                        if (activeCount > cpuCores || queueSize > 5) {
                            try {
                                // 根据负载动态调整等待时间，更长的等待时间
                                long waitTime = Math.min(1000 + (activeCount * 100), 5000); // 最多等待5秒
                                log.info("线程池负载较高[活跃线程:{}, 队列:{}], 等待{}ms",
                                        activeCount, queueSize, waitTime);
                                Thread.sleep(waitTime);
                            } catch (InterruptedException e) {
                                Thread.currentThread().interrupt();
                                log.warn("线程池负载控制等待被中断");
                            }
                        } else {
                            // 即使负载不高，也添加一个小的间隔来降低请求频率
                            try {
                                Thread.sleep(500); // 固定等待500ms
                                log.debug("任务提交间隔: 等待500ms");
                            } catch (InterruptedException e) {
                                Thread.currentThread().interrupt();
                            }
                        }
                    }
                }

                // 等待所有数据获取任务完成
                try {
                    log.info("开始等待所有数据获取任务完成，共{}个任务", futures.size());
                    // 增加超时时间，避免大量数据时超时
                    CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(30, TimeUnit.MINUTES);
                    log.info("所有数据获取任务已完成");

                    // 等待数据保存线程池中的任务完成，使用更可靠的方式
                    if (dataSaveExecutor instanceof ThreadPoolExecutor) {
                        ThreadPoolExecutor saveExecutor = (ThreadPoolExecutor) dataSaveExecutor;
                        log.info("开始等待数据保存任务完成，当前活跃线程数: {}, 队列大小: {}",
                                saveExecutor.getActiveCount(), saveExecutor.getQueue().size());

                        // 给保存线程池更多时间来处理队列中的任务
                        int maxWaitSeconds = 120; // 增加到120秒
                        int waitedSeconds = 0;

                        // 记录初始任务数，用于计算进度
                        int initialActiveCount = saveExecutor.getActiveCount();
                        int initialQueueSize = saveExecutor.getQueue().size();
                        int totalTasks = initialActiveCount + initialQueueSize;

                        while (saveExecutor.getActiveCount() > 0 || saveExecutor.getQueue().size() > 0) {
                            if (waitedSeconds >= maxWaitSeconds) {
                                log.warn("等待数据保存任务超时({}秒)，仍有任务未完成，活跃线程数: {}, 队列大小: {}",
                                        maxWaitSeconds, saveExecutor.getActiveCount(), saveExecutor.getQueue().size());
                                // 即使超时也继续执行，不中断流程
                                break;
                            }

                            // 计算完成百分比
                            int currentTasks = saveExecutor.getActiveCount() + saveExecutor.getQueue().size();
                            int completedTasks = totalTasks - currentTasks;
                            double percentComplete = totalTasks > 0 ? (completedTasks * 100.0 / totalTasks) : 100.0;

                            Thread.sleep(1000); // 等待1秒
                            waitedSeconds++;

                            if (waitedSeconds % 5 == 0) { // 每5秒记录一次日志
                                log.info("等待数据保存任务完成中...已等待{}秒，活跃线程数: {}, 队列大小: {}, 完成进度: {:.2f}%",
                                        waitedSeconds, saveExecutor.getActiveCount(), saveExecutor.getQueue().size(), percentComplete);
                            }
                        }
                        log.info("数据保存任务已全部完成或等待超时");
                    } else {
                        log.warn("数据保存线程池不是ThreadPoolExecutor类型，无法等待任务完成");
                    }
                } catch (Exception e) {
                    log.error("等待数据获取或保存任务完成时发生异常: {}", e.getMessage(), e);
                    // 即使出现异常，也继续执行后续代码，不中断整个流程
                }

                // 按页码顺序将所有数据添加到结果列表
                for (int pageIndex = startPageIndex; pageIndex <= endPageIndex; pageIndex++) {
                    List<MajorAdmissionInfo> pageData = pageDataMap.get(pageIndex);
                    if (pageData != null && !pageData.isEmpty()) {
                        allAdmissionList.addAll(pageData);
                    }
                }
            }

            // 构建返回结果
            result.put("success", true);
            result.put("admissionList", allAdmissionList);
            result.put("totalCount", totalCount);
            result.put("distinctSchoolCount", distinctSchoolCount);
            result.put("pageIndex", 1); // 因为返回了所有数据，所以页码固定为1
            result.put("pageSize", allAdmissionList.size()); // 页面大小就是所有数据的数量
            result.put("totalPages", totalPages); // 返回实际总页数
            result.put("isAllData", true); // 标记这是所有数据
            result.put("startPageIndex", reqVO.getStartPageIndex() != null ? reqVO.getStartPageIndex() : 1);
            result.put("endPageIndex", reqVO.getEndPageIndex() != null ? reqVO.getEndPageIndex() : totalPages);

            return result;
        } catch (Exception e) {
            result.put("success", false);
            result.put("message", "查询历年高考专业录取数据失败: " + e.getMessage());
            return result;
        }
    }

    @Override
    public List<MajorAdmissionDO> getMajorAdmissionBySchoolMajorYearTypeNameprovinceName(String schoolUUID, String majorName, Integer year, String typeName, String provinceName) {
        return majorAdmissionMapper.selectBySchoolMajorYearTypeNameProvinceName(schoolUUID, majorName, year,typeName,provinceName);
    }

    @Override
    public List<MajorAdmissionDO> getMajorAdmissionByProvinceAndYear(String provinceName, Integer year) {
        return majorAdmissionMapper.selectByProvinceAndYear(provinceName, year);
    }

    @Override
    public List<MajorAdmissionDO> getMajorAdmissionBySchoolName(String schoolName) {
        return majorAdmissionMapper.selectBySchoolName(schoolName);
    }

    @Override
    public List<MajorAdmissionDO> getMajorAdmissionByMajorName(String majorName) {
        return majorAdmissionMapper.selectByMajorName(majorName);
    }

    @Override
    public List<MajorAdmissionDO> getMajorAdmissionByYear(Integer year) {
        return majorAdmissionMapper.selectByYear(year);
    }

    @Override
    public List<MajorAdmissionDO> getMajorAdmissionBySubjectGroup(String subjectGroup) {
        return majorAdmissionMapper.selectBySubjectGroup(subjectGroup);
    }

    @Override
    public List<MajorAdmissionDO> getMajorAdmissionBySchoolMajorYearTypeNameProvinceNameAndSubjectGroup(String schoolUUID, String majorName, Integer year, String typeName, String provinceName, String subjectGroup) {
        return majorAdmissionMapper.selectBySchoolMajorYearTypeNameProvinceNameAndSubjectGroup(schoolUUID, majorName, year, typeName, provinceName, subjectGroup);
    }

    @Override
    public List<MajorAdmissionDO> getMajorAdmissionByProvinceYearAndScoreRange(String provinceName, Integer year, Integer minScore, Integer maxScore) {
        return majorAdmissionMapper.selectByProvinceYearAndScoreRange(provinceName, year, minScore, maxScore);
    }

    @Override
    public List<MajorAdmissionDO> getMajorAdmissionByProvinceYearScoreRangeAndMajorName(String provinceName, Integer year, Integer minScore, Integer maxScore, String majorName) {
        return majorAdmissionMapper.selectByProvinceYearScoreRangeAndMajorName(provinceName, year, minScore, maxScore, majorName);
    }

    @Override
    public List<MajorAdmissionDO> getMajorAdmissionByProvinceYearScoreRangeAndMajorKeywords(String provinceName, Integer year, Integer minScore, Integer maxScore, String majorName) {
        return majorAdmissionMapper.selectByProvinceYearScoreRangeAndMajorKeywords(provinceName, year, minScore, maxScore, majorName);
    }

    @Override
    public List<MajorAdmissionDO> batchQueryAdmissionScores(List<String> schoolUUIDs, List<String> majorNames, Integer year, String typeName, String provinceName) {
        return majorAdmissionMapper.batchSelectAdmissionScores(schoolUUIDs, majorNames, year, typeName, provinceName);
    }

    @Override
    public List<MajorAdmissionDO> batchQueryAdmissionScoresWithSubjectGroup(List<String> schoolUUIDs, List<String> majorNames, Integer year, String typeName, String provinceName, String subjectGroup) {
        return majorAdmissionMapper.batchSelectAdmissionScoresSimpleWithSubjectGroup(schoolUUIDs, majorNames, year, typeName, provinceName, subjectGroup);
    }

    @Override
    public Map<String, Object> batchProcessMajorNameBracketContent(int batchSize, int threadCount) {
        log.info("开始批量处理专业录取表中的专业名称括号内容，批次大小: {}, 线程数: {}", batchSize, threadCount);

        Map<String, Object> result = new HashMap<>();
        long startTime = System.currentTimeMillis();

        try {
            // 1. 统计需要处理的数据量
            long totalRecords = majorAdmissionMapper.selectCount(null);
            long recordsWithBrackets = majorAdmissionMapper.selectCount(
                new LambdaQueryWrapperX<MajorAdmissionDO>()
                    .and(w -> w.like(MajorAdmissionDO::getMajorName, "（")
                               .or().like(MajorAdmissionDO::getMajorName, "("))
            );

            log.info("专业录取表数据统计 - 总记录数: {}, 包含括号的记录数: {}", totalRecords, recordsWithBrackets);

            if (recordsWithBrackets == 0) {
                result.put("success", true);
                result.put("message", "没有需要处理的数据");
                result.put("totalRecords", totalRecords);
                result.put("processedRecords", 0);
                return result;
            }

            // 2. 分批处理数据
            AtomicInteger processedCount = new AtomicInteger(0);
            AtomicInteger updatedCount = new AtomicInteger(0);

            // 创建线程池
            ExecutorService executor = Executors.newFixedThreadPool(threadCount);
            List<CompletableFuture<Void>> futures = new ArrayList<>();

            // 计算总批次数
            int totalBatches = (int) Math.ceil((double) recordsWithBrackets / batchSize);
            log.info("预计需要处理 {} 个批次", totalBatches);

            for (int batch = 0; batch < totalBatches; batch++) {
                final int currentBatch = batch;
                final int offset = batch * batchSize;

                CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                    try {
                        processBatchMajorAdmissionBracketContent(offset, batchSize, processedCount, updatedCount, currentBatch + 1, totalBatches);
                    } catch (Exception e) {
                        log.error("处理第{}批专业录取数据时发生异常", currentBatch + 1, e);
                    }
                }, executor);

                futures.add(future);
            }

            // 等待所有任务完成
            CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
            executor.shutdown();

            long endTime = System.currentTimeMillis();
            long duration = endTime - startTime;

            result.put("success", true);
            result.put("message", "专业录取表括号内容批量处理完成");
            result.put("totalRecords", totalRecords);
            result.put("recordsWithBrackets", recordsWithBrackets);
            result.put("processedRecords", processedCount.get());
            result.put("updatedRecords", updatedCount.get());
            result.put("duration", duration);
            result.put("durationFormatted", formatDuration(duration));

            log.info("专业录取表批量处理完成 - 处理记录数: {}, 更新记录数: {}, 耗时: {}ms",
                    processedCount.get(), updatedCount.get(), duration);

        } catch (Exception e) {
            log.error("批量处理专业录取表专业名称括号内容失败", e);
            result.put("success", false);
            result.put("message", "处理失败: " + e.getMessage());
        }

        return result;
    }

    /**
     * 处理单个批次的专业录取表专业名称括号内容
     */
    private void processBatchMajorAdmissionBracketContent(int offset, int batchSize,
                                                        AtomicInteger processedCount, AtomicInteger updatedCount,
                                                        int currentBatch, int totalBatches) {
        try {
            // 查询包含括号的数据
            List<MajorAdmissionDO> records = majorAdmissionMapper.selectList(
                new LambdaQueryWrapperX<MajorAdmissionDO>()
                    .and(w -> w.like(MajorAdmissionDO::getMajorName, "（")
                               .or().like(MajorAdmissionDO::getMajorName, "("))
                    .last("LIMIT " + offset + ", " + batchSize)
            );

            if (records.isEmpty()) {
                log.debug("第{}批没有找到需要处理的专业录取数据", currentBatch);
                return;
            }

            int batchUpdated = 0;

            for (MajorAdmissionDO record : records) {
                try {
                    String originalName = record.getMajorName();
                    if (originalName == null || originalName.trim().isEmpty()) {
                        continue;
                    }

                    // 使用工具类处理专业名称
                    MajorNameBracketProcessor.MajorNameProcessResult processResult =
                        MajorNameBracketProcessor.processMajorName(originalName);

                    // 如果有括号内容，则更新记录
                    if (processResult.hasBracketContent()) {
                        record.setMajorName(processResult.getCleanMajorName());
                        record.setMajorNameBracketContent(processResult.getBracketContent());

                        majorAdmissionMapper.updateById(record);
                        batchUpdated++;

                        if (log.isDebugEnabled()) {
                            log.debug("更新专业录取记录 ID: {}, 原名称: {}, 新名称: {}, 括号内容: {}",
                                    record.getId(), originalName, processResult.getCleanMajorName(),
                                    processResult.getBracketContent());
                        }
                    }

                } catch (Exception e) {
                    log.error("处理专业录取记录 ID: {} 时发生异常", record.getId(), e);
                }
            }

            processedCount.addAndGet(records.size());
            updatedCount.addAndGet(batchUpdated);

            log.info("完成第{}/{}批专业录取数据处理，本批处理{}条记录，更新{}条记录，累计处理{}条",
                    currentBatch, totalBatches, records.size(), batchUpdated, processedCount.get());

        } catch (Exception e) {
            log.error("处理第{}批专业录取数据时发生异常", currentBatch, e);
        }
    }

    @Override
    public List<MajorAdmissionDO> getMajorAdmissionByProvinceYearScoreRangeAndType(String provinceName, Integer year, Integer minScore, Integer maxScore, String typeName) {
        return majorAdmissionMapper.selectByProvinceYearScoreRangeAndType(provinceName, year, minScore, maxScore, typeName);
    }

    /**
     * 控制API请求频率，避免请求过快触发限流
     */
    private void controlRequestRate() {
        long currentTime = System.currentTimeMillis();
        long elapsedTime = currentTime - lastRequestTime;

        if (lastRequestTime > 0 && elapsedTime < MIN_REQUEST_INTERVAL) {
            // 如果距离上次请求的时间小于最小间隔，则等待
            long sleepTime = MIN_REQUEST_INTERVAL - elapsedTime;
            try {
                log.debug("请求频率控制: 上次请求距现在{}ms, 需要等待{}ms", elapsedTime, sleepTime);
                Thread.sleep(sleepTime);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                log.warn("请求频率控制等待被中断");
            }
        } else if (lastRequestTime > 0) {
            log.debug("请求频率控制: 上次请求距现在{}ms, 无需等待", elapsedTime);
        }

        // 更新最后请求时间
        lastRequestTime = System.currentTimeMillis();
    }

    /**
     * 将MajorAdmissionInfo转换为MajorAdmissionDO
     *
     * @param admissionInfo MajorAdmissionInfo对象
     * @return MajorAdmissionDO对象
     */
    private MajorAdmissionDO convertToMajorAdmissionDO(MajorAdmissionInfo admissionInfo) {
        if (admissionInfo == null) {
            return null;
        }

        return MajorAdmissionDO.builder()
                .provinceName(admissionInfo.getProvinceName())
                .schoolUuid(admissionInfo.getSchoolUUID())
                .schoolName(admissionInfo.getSchoolName())
                .majorName(admissionInfo.getMajorName())
                .majorCode(admissionInfo.getMajorCode())
                .year(admissionInfo.getYear())
                .highScore(admissionInfo.getHighScore())
                .averageScore(admissionInfo.getAverageScore())
                .lowestScore(admissionInfo.getLowestScore())
                .lowestSection(admissionInfo.getLowestSection())
                .batchName(admissionInfo.getBatchName())
                .typeName(admissionInfo.getTypeName())
                .proScore(admissionInfo.getProScore())
                .subjectSelection(admissionInfo.getSubjectSelection())
                .subjectGroup(admissionInfo.getSubjectGroup())
                .majorStandardCode(admissionInfo.getMajorStandardCode())
                .majorNameBracketContent(admissionInfo.getMajorNameBracketContent())
                .build();
    }

    /**
     * 格式化持续时间
     */
    private String formatDuration(long milliseconds) {
        long seconds = milliseconds / 1000;
        long minutes = seconds / 60;
        long hours = minutes / 60;

        if (hours > 0) {
            return String.format("%d小时%d分钟%d秒", hours, minutes % 60, seconds % 60);
        } else if (minutes > 0) {
            return String.format("%d分钟%d秒", minutes, seconds % 60);
        } else {
            return String.format("%d秒", seconds);
        }
    }
}
